<?php
namespace App\GameService\games;

use App\Utility\BaseEnum;
use App\Utility\RedisTools;
use App\Enum\SysEnum;
use App\Common\BaseComm;

/**
 * 公共的数据操作
 * @author Administrator
 */
class PlayHelp
{
    protected static $instance = null;              //保存全局实例对象
    protected $dsqTimes   = [];                     //定时器里的秒数剩余值
    protected $gameRoomPlayers   = [];              //匹配玩家列表信息(百人牛牛加入在线玩家列表 [1050=> [uid=> object ]])
    protected $gamePlayMoney   = [];                //玩家虚拟金额值
    protected $plyerGameNoLists  = [];              //玩家房间列表数据
    protected $gameCommonTimer   = [];              //玩家房间对应的终止定时器；默认每个房间都是[gameNo=>false]
    protected $gameRoomCards     = [];              //玩家房间的开牌数据
    protected $playerOpenHands     = [];            //玩家房间的开牌数据
    protected $gameResultLogs = [];
    protected $lockDataList = [];                   //加唯一锁存数据
    private $commtime_key = '';
    //事件 
    public function __construct() {
        $this->commtime_key = SysEnum::BASEDB_GAMECOMMON_TIMERS_KEY;
    }
    
    /**
     * 单例访问统一入口
     * @return 本对象类；
     */
    public static function getInstance()  {
        if(!(self::$instance instanceof self)) { 
            self::$instance = new self(); 
        }
        return self::$instance;
    }
    
    
    /**
     * TODO 标识定时器停掉；
     * @param string $gameNo
     */
    public function setCommTimerStop($gameNo,$status = FALSE) :void {
        $statusval = ($status=== TRUE) ?  1: 0 ; 
        if($status === FALSE){
            //unset($this->gameCommonTimer[$gameNo]);
            RedisTools::Pool_hDel($this->commtime_key, $gameNo);
            //BaseEnum::Logger("CLEAR::======>>>> 清空{$gameNo}的定时器紧急开关(editval={$statusval})");
        }else{
            //$this->gameCommonTimer[$gameNo] =  1 ;
            RedisTools::Pool_hSet($this->commtime_key, $gameNo , 1);
            //BaseEnum::Logger("EDIT::======>>>> 修改{$gameNo}的定时器紧急开关(editval={$statusval})");
        }
    }
    
    /**
     * TODO 定时器是否有停止标识
     * @param string $gameNo
     */
    public function getCommTimerStop($gameNo) {
        //$saveValue = $this->gameCommonTimer[$gameNo] ?? 0;
        $saveValue = RedisTools::Pool_hGet($this->commtime_key, $gameNo);
        if (intval($saveValue) === 1) $saveValue = 1;
        //BaseEnum::Logger("GET::======>>>> 获取{$gameNo}的定时器紧急开关(getStatus====>{$saveValue})");
        return $saveValue==1 ? TRUE : FALSE;
    }
    
    
    /**
     * TODO 标识玩家即时操作存入
     * @param string $userId
     */
    public function setPlayerOpenHands($userId,$handType = FALSE) :void {
        if($handType === FALSE && isset($this->playerOpenHands[$userId])){
            unset($this->playerOpenHands[$userId]) ;
        }
        if($handType !== FALSE){
            $this->playerOpenHands[$userId] =  $handType ;
        }
        BaseEnum::Logger("内存playerOpenHands=".json_encode($this->playerOpenHands));
    }
    
    /**
     * TODO 标识玩家即时操作取出
     * @param string $userId
     */
    public function getPlayerOpenHands($userId) {
        $result = FALSE;
        if (!empty($this->playerOpenHands) && $userId > 0) {
            $result = $this->playerOpenHands[$userId] ?? FALSE; 
        }
        BaseEnum::Logger("内存playerOpenHands=".json_encode($this->playerOpenHands));
        return $result;
    }
    
    
    //TODO 设置值
    public function setLoopTim($gameId, $time= FALSE) :void {
        if ($time === FALSE) {
            if(isset($this-> dsqTimes[$gameId])){
                unset($this-> dsqTimes[$gameId]); //清空房间里的数据；
            }
        }else{
            $this -> dsqTimes[$gameId] = $time ; //保存数据到对象中；
        }
    }
    
    //TODO 获取值
    public function getLoopTim($gameId = FALSE) {
        if(!$gameId) return $this-> dsqTimes;
        if (!empty($this-> dsqTimes) && isset($this-> dsqTimes[$gameId])) {
            return $this-> dsqTimes[$gameId];
        } return FALSE;
    }
    
    
    /**
     * TODO 玩家虚拟币
     * @param int $gameRid
     * @return array 玩家列表值；
     */
    public function getPlayMoney($userId = FALSE) {
        if(!$userId) return $this-> gamePlayMoney;
        if (!empty($this-> gamePlayMoney) && isset($this-> gamePlayMoney[$userId])) {
            return $this-> gamePlayMoney[$userId];
        } 
        return FALSE;
    }
    
    /**
     * TODO 玩家虚拟币变更 
     * TODO 设置成功不返回
     */
    public function setPlayMoney($userId, $roomFeelist = FALSE) :void {
        if ($roomFeelist === FALSE) {
            if(isset($this-> gamePlayMoney[$userId])){
                unset($this-> gamePlayMoney[$userId]); //清空房间里的数据；
            }
        }else if(!empty($roomFeelist)){
            $this -> gamePlayMoney[$userId] = $roomFeelist ; //保存数据到对象中；
        }
    }
    
    /**
     * TODO 获取所有房间游戏信息
     */
    public function  getGameRoomsData($gameNo, $other = FALSE) {
        if(!$gameNo) return $this-> plyerGameNoLists;
        if (!empty($this-> plyerGameNoLists) && isset($this-> plyerGameNoLists[$gameNo])) {
            return $this-> plyerGameNoLists[$gameNo]; //整个房间内所有玩家数据
        } return FALSE;
    }
    
    /**
     *  TODO所有房间保存玩家的游戏信息
     *  TODO 设置成功不返回
     */
    public function setGameRoomsData($gameNo, $gameRoomData = FALSE) :void {
        if ($gameRoomData === FALSE) {  
            if(isset($this-> plyerGameNoLists[$gameNo])) {
                unset($this-> plyerGameNoLists[$gameNo]);       //清空数据
            }
        }else if(!empty($gameRoomData)){
            $this->plyerGameNoLists[$gameNo] = $gameRoomData ; //保存数据到对象中；
        }
    }
    
    /**
     * TODO 玩家匹配列表
     * @param int $gameRid
     * @return array 玩家列表值；
     */
    public function getRoomPlayers($gameRid = FALSE) {
        if(!$gameRid) return $this-> gameRoomPlayers;        
        if (!empty($this-> gameRoomPlayers) && isset($this-> gameRoomPlayers[$gameRid])) {
            //整个房间ID下等待游戏人的信息；
            return $this-> gameRoomPlayers[$gameRid]; 
        } return FALSE;
    }
    
    /**
     * TODO 加入到房间(整体存储和删除)
     * TODO 设置成功不返回
     */
    public function setRoomPlayers($gameRid, $playerList = FALSE) :void {
        if ($playerList === FALSE) {
            if(isset($this-> gameRoomPlayers[$gameRid])){
                unset($this-> gameRoomPlayers[$gameRid]); //清空房间里的数据；
            }  
        }else if(!empty($playerList)){
            
            $this -> gameRoomPlayers[$gameRid] = $playerList ; //保存数据到对象中；
        }
    }

    
    /**
     *TODO  取每个游戏牌的数据；
     * @param string $gameNo 游戏号
     */
    public function getRoomCards($gameNo) {
        if(!$gameNo) return $this-> gameRoomCards;
        if (!empty($this-> gameRoomCards) && isset($this-> gameRoomCards[$gameNo])) {
            return $this-> gameRoomCards[$gameNo];  //整个房间内所有玩家数据
        } return FALSE;
    }
    
    /**
     * TODO 保存牌的数据内容
     * @param string $gameNo 游戏号
     * @param boolean $cardList
     */
    public function setRoomCards($gameNo,$cardList = FALSE) :void {
        if ($cardList === FALSE) {
            if(isset($this-> gameRoomCards[$gameNo])){
                unset($this-> gameRoomCards[$gameNo]); //清空牌数据；
            }
        }else if(!empty($cardList)){
            $this -> gameRoomCards[$gameNo] = $cardList ; //保存牌
        }
    }

    /**
     * TODO 保存游戏结果数据（现只用在百人牛牛）
     * @param $first string 游戏房间ID值
     * @param $second string 二维下标
     * @param bool $resultArr resultArr
     */
    public function setResultLog($gameRid,$second,$resultArr = FALSE) :void {
        if ($resultArr === FALSE) {
            if(isset($this-> gameResultLogs[$gameRid][$second])){
                unset($this-> gameResultLogs[$gameRid][$second]);
            }
        }else if(!empty($resultArr)){
            $this -> gameResultLogs[$gameRid][$second] = $resultArr;
        }
    }

    /**
     * TODO 获取游戏结果值数据
     * @param int $gameRid    房间ID值
     * @param string $second  第二层数据结构
     * @return boolean|mixed 
     */
    public function getResultLog($gameRid,$second = FALSE) {
        if(!$gameRid) return FALSE;
        if ($gameRid && !$second)  return $this->gameResultLogs[$gameRid];
        if (!empty($this-> gameResultLogs) && isset($this-> gameResultLogs[$gameRid][$second])) {
            return $this-> gameResultLogs[$gameRid][$second];
        } return FALSE;
    }


    
    
    /**
     * TODO 加锁取原始数据 (自动解锁)
     * @param string $key 唯一值
     */
    public function getLuckResult($key,$expire = 2000) {
        $lastRes = FALSE;
        $nowtime = BaseComm::getMillisecond();
        $youdata = $this->lockDataList[$key] ?? FALSE;              //原有数据内容；加锁功能
        if($youdata == FALSE){
            return FALSE;
        }
        $isLok = $youdata["lk"] ?? FALSE;
        $lokStamp = $youdata["ltm"] ?? 0;
        $lastRes = $youdata["data"] ?? FALSE;
        
        //TODO 已加锁情况，等待解锁再获取
        if (!empty($youdata) && $isLok === TRUE) {                  //加锁拿数据
            if($lokStamp <= 0 || $nowtime - $lokStamp < $expire){
                
                //TODO 超时未处理(0)
                for ($i = 0; $i < 5; $i++) {
                    @usleep(500 * 1000);                            //休息0.5秒去查看是否解锁
                    $secdata = $this->lockDataList[$key] ?? FALSE;  //原有数据内容；加锁功能
                    $isLok = $secdata["lk"] ?? FALSE;
                    
                    //TODO 是否释放锁
                    if ($isLok !== TRUE) {
                        $lastRes = $secdata["data"] ?? FALSE;       //最新数据
                        break;
                    }
                }
            }
        }
        return $lastRes; 
    }
    
    
    
    /**
     * TODO 解锁更新数据(自动解锁)
     * @param string $key 唯一值
     */
    public function unLuck($key) {
        BaseEnum::Logger("释放前:  ====> : [{$key}])==>" . json_encode($this->lockDataList), 'user-login');
        if(!empty($this->lockDataList) && array_key_exists($key, $this->lockDataList)){
            unset($this->lockDataList[$key]);
            BaseEnum::Logger("释放锁 SUCCESS====> : [{$key}])==>" . json_encode($this->lockDataList), 'user-login');
        }
    }
    
    public function getLocked($key,$data) {
        $youdata = $this->lockDataList[$key] ?? FALSE;              //原有数据内容；加锁功能
        BaseEnum::Logger("查看锁数据=========，是否有锁 : [{$key}])==>" . json_encode($this->lockDataList), 'user-login');
        /* if (!empty($youdata) && $youdata == $data) {  return TRUE; }
        return FALSE; */
        return $youdata??FALSE ;
    }
    /**
     * TODO 解锁更新数据(自动解锁)
     * @param string $key 唯一值
     */
    public function addLuck($key,$data,$expire = 2000) {
        $this->lockDataList[$key] = $data;
    }
    
    /* public function getLocked($key,$data,$roomId) {
        $youdata = $this->lockDataList[$key] ?? FALSE;              //原有数据内容；加锁功能
        BaseEnum::Logger("查看锁数据=========，是否有锁 : [{$key}]-{$data})==>" . json_encode($this->lockDataList), 'user-login');
        if (!empty($youdata) && $youdata !== $data) {
            //等待解锁
            for ($i = 0; $i < 20; $i++) {
                @usleep(100*1000);
                $youdata = $this->lockDataList[$key] ?? FALSE;      //直到锁释放加自己的锁
                $tempArr = BaseComm::distMemoryRooms($roomId, FALSE);                // 内存
                $userBets = isset($tempArr['list']) ? $tempArr['list'] : FALSE;
                BaseEnum::Logger("等待锁， : [{$roomId}-{$data}])==>" . json_encode($userBets), 'user-login');
                if($youdata == false){
                    BaseEnum::Logger("获取锁， : [{$roomId}- {$data}])==>" . json_encode($userBets), 'user-login');
                    $this->addLuck($key,$data);                  
                    return true;
                }
            } 
        }else{
            $youdata = $this->lockDataList[$key] ?? FALSE;      //直到锁释放加自己的锁
            $tempArr = BaseComm::distMemoryRooms($roomId, FALSE);                // 内存
            $userBets = isset($tempArr['list']) ? $tempArr['list'] : FALSE;
            BaseEnum::Logger("第一次获取锁， : [{$roomId}] - {$data})==>" . json_encode($userBets), 'user-login');
            $this->addLuck($key, $data);                            //没锁加自己的锁
            return true;
        }
        return true;                                                //多次获取不到避免死锁
    } */
}

?>